package netty.socket;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import netty.mqtt.BeverageMixerData;
import netty.mqtt.MqttCommonMsg;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.time.Instant;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * plc数据管理器
 *
 * @author zhangtao
 * @date 2021/11/23
 */
@Slf4j
public class McSocket implements MqttCallback {

    private static final int CONNECT_TIME_OUT = 100;

    private String mHost;

    private String mUserName;

    private String mPassWord;

    private String[] mTopics;

    private String mClientId;

    private int mKeepAlive;

    private MqttClient mClient;

    private MqttConnectOptions mOptions;

    private static McSocket plcDataManager;

    public static synchronized McSocket getInstance() {
        if (null == plcDataManager) {
            plcDataManager = new McSocket();
        }
        return plcDataManager;
    }

    private McSocket() {
    }

    public void start() {
        init("tcp://10.218.223.247:1883", null, null,
                new String[]{"device/smartsocket/data", "device/smartsocket/ack","device/smartsocket/data/Mc-943cc6a006a8"}, "mcSocketTest", 10);
        initClient();
        connect();
    }

    public void init(String host, String userName, String passWord, String[] topic, String clientId,
                     int keepAlive) {
        this.mHost = host;
        this.mUserName = userName;
        this.mPassWord = passWord;
        this.mTopics = topic;
        this.mClientId = clientId;
        this.mKeepAlive = keepAlive;
    }

    private void initClient() {
        try {
            mClient = new MqttClient(mHost, mClientId, new MemoryPersistence());
            mOptions = new MqttConnectOptions();
            mOptions.setCleanSession(true);
            if (mUserName != null) {
                mOptions.setUserName(mUserName);
            }
            if (mPassWord != null) {
                mOptions.setPassword(mPassWord.toCharArray());
            }
            mOptions.setConnectionTimeout(CONNECT_TIME_OUT);
            mOptions.setKeepAliveInterval(mKeepAlive);
            mClient.setCallback(this);
        } catch (Exception e) {
            log.info("init client error:" + e.getMessage());
        }
    }

    private void connect() {
        if (null == mClient) {
            log.error("mqtt client[{}] is null", mClientId);
            return;
        }
        if (mClient.isConnected()) {
            log.error("mqtt client[{}] is connected", mClientId);
            return;
        }
        new Thread(() -> {
            try {
                mClient.connect(mOptions);
                mClient.subscribe(mTopics);
            } catch (Exception e) {
                log.info("connect Mqtt server error:" + e.getMessage());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                connect();
            }
        }).start();
    }

    public boolean sendMessage(byte[] messagePayload, String topic, int qos) {
        if (mClient != null) {
            try {
                mClient.getDebug().dumpClientComms();
                log.info("topic[{}] message[{}]", topic, new String(messagePayload));
                mClient.getTopic(topic).publish(messagePayload, qos, false);
                return true;
            } catch (Exception e) {
                log.info("Failed to send outbound message (unexpected issue): " + new String(messagePayload));
                log.info(e.getLocalizedMessage());
                e.printStackTrace();
            }
        }
        return false;

    }

    public boolean sendMessage(byte[] messagePayload, String topic, int qos, boolean retained) {
        if (mClient != null) {
            try {
                mClient.getTopic(topic).publish(messagePayload, qos, retained);
                return true;
            } catch (Exception e) {
                log.info("Failed to send outbound message (unexpected issue): " + new String(messagePayload));
                log.info(e.getLocalizedMessage());
                e.printStackTrace();
            }
        }
        return false;

    }

    @Override
    public void connectionLost(Throwable throwable) {
        log.info("mqtt client connect lost:");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            log.error("", e);
        }
        connect();
    }

    @Override
    public void messageArrived(String mqttTopic, MqttMessage mqttMessage) {
        try {
            if (mqttMessage == null || mqttTopic == null) {
                return;
            }
            log.info("topic[{}] message[{}]", mqttTopic, mqttMessage);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }


    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        // TODO Auto-generated method stub
    }


    public void send() {
        MqttCommonMsg msg = new MqttCommonMsg();
        msg.setSpid(UUID.randomUUID().toString());
        msg.setTid("DB6661");
        msg.setType("ACK");
        msg.setTime(Instant.now().getEpochSecond());

        BeverageMixerData data = new BeverageMixerData();
        data.setWorkMode("手动模式");
        data.setWorkNumber(100);
        data.setWorkState("屏保状态");
        data.setWorkStatus(1);
        data.setIsolationCoverState(true);

        msg.setData(new Gson().toJson(data));
        sendMessage(new Gson().toJson(msg).getBytes(), "device/drinkblender/pub", 1);
    }

    public static void main(String[] args) throws InterruptedException {
        McSocket test = McSocket.getInstance();
        test.start();
//        Thread.sleep(10000);
//        String json = "{\n" +
//                "\"spid\": 1,\n" +
//                "\"tid\":\"Mc-943cc69a90bc\",\n" +
//                "\"time\": 1644219101,\n" +
//                "\"type\":\"READINFO\"\n" +
//                "}\n";
//        test.sendMessage(json.getBytes(), "device/smartsocket/data/Mc-943cc6a006a8", 1);
    }
}
